package com.hss.nestscroll.NewsDetail;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;

public class MyNestScrollChild extends LinearLayout implements NestedScrollingChild {
    NestedScrollingChildHelper mScrollingChildHelper ;

    private final int[] mScrollOffset = new int[2];
    private final int[] mScrollConsumed = new int[2];//是为了给父控件传递来计算消耗值的变量（上面说的int[] consumed）
    private int mLastTouchY;//是为了来计算滑动偏移
    private int mVisiableHeight;
    private int mFullHeight;
    private int mCanScrollY;
//三者共同计算出了Child可以滑动的距离

    public MyNestScrollChild(Context context) {
        this(context, null);
    }

    public MyNestScrollChild(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyNestScrollChild(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScrollingChildHelper = new NestedScrollingChildHelper(this);
        mScrollingChildHelper.setNestedScrollingEnabled(true);
    }

    @Override
    public boolean startNestedScroll(int axes) {
        return mScrollingChildHelper.startNestedScroll(axes);
    }


    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {
        return mScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastTouchY = (int) (event.getRawY()+0.5f);
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);

                break;
            /**
             * 结合之前说的Parent的onNestedPreScroll，我们就能很容易理解Child里的这段代码的含义。
             * dispatchNestedPreScroll(0, dy, mScrollConsumed, mScrollOffset)调用后会如果返回了true，
             * 那么证明Parent是要对滑动事件进行消耗的，那么消耗后剩余的就是dy - mScrollConsumed[1];
             * 这和我们之前说的Parent的是一致的
             */
            case  MotionEvent.ACTION_MOVE:
                int y = (int) (event.getRawY() + 0.5f);
                int dy = mLastTouchY - y;
                mLastTouchY = y;
                if (dispatchNestedPreScroll(0, dy, mScrollConsumed, mScrollOffset)) {
                    dy -= mScrollConsumed[1];
                }
                scrollBy(0, dy);
                 break;
        }
        return true;
    }

    @Override
    public void scrollTo(int x, int y) {
        if (y > mCanScrollY) {
            y = mCanScrollY;
        }
        if (y < 0) {
            y = 0;
        }
        super.scrollTo(x, y);
    }

    /**
     * onMeasure我们在里面计算mCanScrollY-Child可以滑动的距离。为什么会有这个过程？因为既然Child能滑动，
     * 那么它看到的大小和它内部的大小就不会一致，两者的差就是可以滑动的距离。
     * 第一次执行的时候计算出mVisiableHeight-即我们看到的大小，
     * 第二次的时候计算mFullHeight-即里面内容的实际高度，然后两者的插值就是mCanScrollY-可以滑动的距离。
     顺便提一句MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);之前在写View的绘制过程时说过，
     这个就是父控件不去限制子控件的大小，所以子控件会自己决定自己的大小，这样就能量出实际内容的大小了，
     这个0可以随便传。
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mVisiableHeight <= 0){
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            mVisiableHeight = getMeasuredHeight();
        }else {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if (mFullHeight <= 0) {
                mFullHeight = getMeasuredHeight();
                mCanScrollY = mFullHeight - mVisiableHeight;
            }
        }

    }
}

/**
从手指点击下去开始Down，在里面可以调用startNestedScroll()，告诉 Parent，Child准备进入滑动状态了，
这时候Parent会被回调onStartNestedScroll()，如果这个方法返回true，代表它接受嵌套滑动，
紧接着Parent会被回调onNestedScrollAccepted()来记录滑动的方向。

 手指滑动Move，需要问一下Parent 是否需要滑动，即调用dispatchNestedPreScroll()，
这时Parent会被回调onNestedPreScroll()。如果Parent要滑动，即消耗事件那么这个就会返回true，
我们需要重新计算一下父类滑动后剩下给你的滑动距离，之后Child进行剩余的滑动，
即调用overScrollByCompat，把滑动距离的参数传给mScroller进行弹性滑动，最后，
如果滑动距离还有剩余，Child就再问一下，Parent 是否需要在继续滑动你剩下的距离，
也就是调用dispatchNestedScroll()。这时候Child就会在滑动之后报告滑动的情况，
即Parent的onNestedScroll会被调用。

手指离开Up,会调用dispatchNestedPreFling，从这里开始，分配fling和分配scroll的过程是一样的，
fling也会有和scroll对应的方法。最后Child调用stopNestedScroll，然后Parent被调用onStopNestedScroll结束滑动。
*/